Open In Colab

Interactive Map For Single and Double Storey Terraced Property Sale For 2022 In Melaka

Project Overview

This project proposes the creation of an interactive map that will contain detailed information about all the single storey and double storey terraced properties sold in Melaka in 2022. The map will serve as a tool for housing developers to develop effective pricing and business strategies for future developments in Melaka, taking into account the current market dynamics.

In 2022, a total of 2870 transactions were made for single storey and double storey terraced houses in Melaka. The property sales for these houses amounted to RM869,477,476.00. These transactions include both freehold and leasehold properties, and cover 457 areas or schemes located in three districts Melaka Tengah, Alor Gajah, and Jasin.

The property market in the state is anticipated to maintain its upward trend, bolstered by the upcoming development projects. These include the Melaka Waterfront Economic Zone (MWEZ) with an expected completion date of 2035, and the ongoing construction of Harbour City Melaka by Hatten Land Ltd. These initiatives are set to have a positive impact on the state's property market.

In [164]:
from IPython.display import display, Image
display(Image(filename='C:/Users/KEMAS/myproject/MWEZ.png'))

Terraced Property Outlook

The property market in Melaka is interesting to watch with the launch of two exciting residential projects: Scientex Durian Tunggal 2 and Bandar Botani Parkland. These developments, spanning 202 acres of land, offer single and double storey terraced homes, making them a prime choice for homebuyers seeking quality living spaces. Keep an eye on these segments, as they are likely to be in high demand in the near future.

Aerial-View-Photo.jpeg

Code and Resources Used • Jupyter Notebook Version: 6.5.4 • Packages: pandas, numpy, scipy, matplotlib, seaborn, plotly express, sklearn, dataframe_image • Dataset Source: https://napic2.jpph.gov.my/ms/data-transaksi?category=36&id=241

Dataset Information •'dataset_2022.csv' contains data from National Property Information Centre (NAPIC). •'latlong.csv' contains latitude and longitude information for scheme name/area. This lat and long information were built from https://postcode.my/location/melaka/ based on scheme name/area from dataset_2022. •'melaka_terraced_property_sales_2022.csv' contains data generated from Jupyter Notebook following cleaning processes.

1. Data Cleaning

In this part, we will begin our exploratory data analysis (EDA) by viewing the dataset_2022.csv.

Setup

In [3]:
import numpy as np
import pandas as pd
import os
import warnings
warnings.filterwarnings("ignore")
!pip install dataframe_image
import dataframe_image as dfi
Defaulting to user installation because normal site-packages is not writeable
Requirement already satisfied: dataframe_image in c:\users\kemas\appdata\roaming\python\python311\site-packages (0.2.3)
Requirement already satisfied: pandas>=0.24 in c:\programdata\anaconda3\lib\site-packages (from dataframe_image) (2.0.3)
Requirement already satisfied: nbconvert>=5 in c:\programdata\anaconda3\lib\site-packages (from dataframe_image) (6.5.4)
Requirement already satisfied: aiohttp in c:\programdata\anaconda3\lib\site-packages (from dataframe_image) (3.8.5)
Requirement already satisfied: requests in c:\programdata\anaconda3\lib\site-packages (from dataframe_image) (2.31.0)
Requirement already satisfied: pillow in c:\programdata\anaconda3\lib\site-packages (from dataframe_image) (10.0.1)
Requirement already satisfied: packaging in c:\programdata\anaconda3\lib\site-packages (from dataframe_image) (23.1)
Requirement already satisfied: mistune in c:\programdata\anaconda3\lib\site-packages (from dataframe_image) (0.8.4)
Requirement already satisfied: lxml in c:\programdata\anaconda3\lib\site-packages (from dataframe_image) (4.9.3)
Requirement already satisfied: beautifulsoup4 in c:\programdata\anaconda3\lib\site-packages (from dataframe_image) (4.12.2)
Requirement already satisfied: cssutils in c:\users\kemas\appdata\roaming\python\python311\site-packages (from dataframe_image) (2.10.2)
Requirement already satisfied: html2image in c:\users\kemas\appdata\roaming\python\python311\site-packages (from dataframe_image) (2.0.4.3)
Requirement already satisfied: bleach in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (4.1.0)
Requirement already satisfied: defusedxml in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (0.7.1)
Requirement already satisfied: entrypoints>=0.2.2 in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (0.4)
Requirement already satisfied: jinja2>=3.0 in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (3.1.2)
Requirement already satisfied: jupyter-core>=4.7 in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (5.3.0)
Requirement already satisfied: jupyterlab-pygments in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (0.1.2)
Requirement already satisfied: MarkupSafe>=2.0 in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (2.1.1)
Requirement already satisfied: nbclient>=0.5.0 in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (0.5.13)
Requirement already satisfied: nbformat>=5.1 in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (5.9.2)
Requirement already satisfied: pandocfilters>=1.4.1 in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (1.5.0)
Requirement already satisfied: pygments>=2.4.1 in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (2.15.1)
Requirement already satisfied: tinycss2 in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (1.2.1)
Requirement already satisfied: traitlets>=5.0 in c:\programdata\anaconda3\lib\site-packages (from nbconvert>=5->dataframe_image) (5.7.1)
Requirement already satisfied: python-dateutil>=2.8.2 in c:\programdata\anaconda3\lib\site-packages (from pandas>=0.24->dataframe_image) (2.8.2)
Requirement already satisfied: pytz>=2020.1 in c:\programdata\anaconda3\lib\site-packages (from pandas>=0.24->dataframe_image) (2023.3.post1)
Requirement already satisfied: tzdata>=2022.1 in c:\programdata\anaconda3\lib\site-packages (from pandas>=0.24->dataframe_image) (2023.3)
Requirement already satisfied: numpy>=1.21.0 in c:\programdata\anaconda3\lib\site-packages (from pandas>=0.24->dataframe_image) (1.24.3)
Requirement already satisfied: attrs>=17.3.0 in c:\programdata\anaconda3\lib\site-packages (from aiohttp->dataframe_image) (22.1.0)
Requirement already satisfied: charset-normalizer<4.0,>=2.0 in c:\programdata\anaconda3\lib\site-packages (from aiohttp->dataframe_image) (2.0.4)
Requirement already satisfied: multidict<7.0,>=4.5 in c:\programdata\anaconda3\lib\site-packages (from aiohttp->dataframe_image) (6.0.2)
Requirement already satisfied: async-timeout<5.0,>=4.0.0a3 in c:\programdata\anaconda3\lib\site-packages (from aiohttp->dataframe_image) (4.0.2)
Requirement already satisfied: yarl<2.0,>=1.0 in c:\programdata\anaconda3\lib\site-packages (from aiohttp->dataframe_image) (1.8.1)
Requirement already satisfied: frozenlist>=1.1.1 in c:\programdata\anaconda3\lib\site-packages (from aiohttp->dataframe_image) (1.3.3)
Requirement already satisfied: aiosignal>=1.1.2 in c:\programdata\anaconda3\lib\site-packages (from aiohttp->dataframe_image) (1.2.0)
Requirement already satisfied: soupsieve>1.2 in c:\programdata\anaconda3\lib\site-packages (from beautifulsoup4->dataframe_image) (2.4)
Requirement already satisfied: websocket-client<2.0.0,>=1.0.0 in c:\users\kemas\appdata\roaming\python\python311\site-packages (from html2image->dataframe_image) (1.8.0)
Requirement already satisfied: idna<4,>=2.5 in c:\programdata\anaconda3\lib\site-packages (from requests->dataframe_image) (3.4)
Requirement already satisfied: urllib3<3,>=1.21.1 in c:\programdata\anaconda3\lib\site-packages (from requests->dataframe_image) (1.26.16)
Requirement already satisfied: certifi>=2017.4.17 in c:\programdata\anaconda3\lib\site-packages (from requests->dataframe_image) (2023.11.17)
Requirement already satisfied: platformdirs>=2.5 in c:\programdata\anaconda3\lib\site-packages (from jupyter-core>=4.7->nbconvert>=5->dataframe_image) (3.10.0)
Requirement already satisfied: pywin32>=300 in c:\programdata\anaconda3\lib\site-packages (from jupyter-core>=4.7->nbconvert>=5->dataframe_image) (305.1)
Requirement already satisfied: jupyter-client>=6.1.5 in c:\programdata\anaconda3\lib\site-packages (from nbclient>=0.5.0->nbconvert>=5->dataframe_image) (7.4.9)
Requirement already satisfied: nest-asyncio in c:\programdata\anaconda3\lib\site-packages (from nbclient>=0.5.0->nbconvert>=5->dataframe_image) (1.5.6)
Requirement already satisfied: fastjsonschema in c:\programdata\anaconda3\lib\site-packages (from nbformat>=5.1->nbconvert>=5->dataframe_image) (2.16.2)
Requirement already satisfied: jsonschema>=2.6 in c:\programdata\anaconda3\lib\site-packages (from nbformat>=5.1->nbconvert>=5->dataframe_image) (4.17.3)
Requirement already satisfied: six>=1.5 in c:\programdata\anaconda3\lib\site-packages (from python-dateutil>=2.8.2->pandas>=0.24->dataframe_image) (1.16.0)
Requirement already satisfied: webencodings in c:\programdata\anaconda3\lib\site-packages (from bleach->nbconvert>=5->dataframe_image) (0.5.1)
Requirement already satisfied: pyrsistent!=0.17.0,!=0.17.1,!=0.17.2,>=0.14.0 in c:\programdata\anaconda3\lib\site-packages (from jsonschema>=2.6->nbformat>=5.1->nbconvert>=5->dataframe_image) (0.18.0)
Requirement already satisfied: pyzmq>=23.0 in c:\programdata\anaconda3\lib\site-packages (from jupyter-client>=6.1.5->nbclient>=0.5.0->nbconvert>=5->dataframe_image) (23.2.0)
Requirement already satisfied: tornado>=6.2 in c:\programdata\anaconda3\lib\site-packages (from jupyter-client>=6.1.5->nbclient>=0.5.0->nbconvert>=5->dataframe_image) (6.3.2)
DEPRECATION: Loading egg at c:\programdata\anaconda3\lib\site-packages\vboxapi-1.0-py3.11.egg is deprecated. pip 23.3 will enforce this behaviour change. A possible replacement is to use pip for package installation..

Data Overview

In [4]:
sales=pd.read_csv('C:/Users/KEMAS/myproject/dataset_2022.csv')
In [5]:
sales.shape
Out[5]:
(2870, 10)
In [6]:
sales.head()
Out[6]:
Property Type District Mukim Scheme Name/Area Month, Year of Transaction Date Tenure Land Area Unit Main Floor Area Transaction Price
0 1 - 1 1/2 Storey Terraced Alor Gajah Bdr Alor Gajah TAMAN SERI BAYU October 2022 Leasehold 143.0 sq.m 85.84 200000
1 1 - 1 1/2 Storey Terraced Alor Gajah Bdr Masjid Tanah TAMAN BKT INDAH July 2022 Freehold 143.0 sq.m 76.64 173000
2 1 - 1 1/2 Storey Terraced Alor Gajah Bdr Masjid Tanah TAMAN BKT INDAH September 2022 Freehold 143.0 sq.m 77.01 210000
3 1 - 1 1/2 Storey Terraced Alor Gajah Belimbing TAMAN BELIMBING HARMONI October 2022 Leasehold 232.0 sq.m 75.72 361111
4 1 - 1 1/2 Storey Terraced Alor Gajah Belimbing TAMAN VISTA BELIMBING January 2022 Freehold 128.0 sq.m 83.61 230000
In [7]:
sales.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2870 entries, 0 to 2869
Data columns (total 10 columns):
 #   Column                           Non-Null Count  Dtype  
---  ------                           --------------  -----  
 0   Property Type                    2870 non-null   object 
 1   District                         2870 non-null   object 
 2   Mukim                            2870 non-null   object 
 3   Scheme Name/Area                 2870 non-null   object 
 4   Month, Year of Transaction Date  2870 non-null   object 
 5   Tenure                           2870 non-null   object 
 6   Land Area                        2870 non-null   float64
 7   Unit                             2870 non-null   object 
 8   Main Floor Area                  2870 non-null   float64
 9   Transaction Price                2870 non-null   int64  
dtypes: float64(2), int64(1), object(7)
memory usage: 224.3+ KB

Check the columns type

In [8]:
print('Column name')
for col in sales.columns:
    if sales[col].dtype=='object':
        print(col, sales[col].nunique())
Column name
Property Type 2
District 3
Mukim 70
Scheme Name/Area 457
Month, Year of Transaction Date 12
Tenure 2
Unit 1
In [9]:
numer = ['Land Area','Main Floor Area','Transaction Price']
for col in numer:
    sales[col] = pd.to_numeric(sales[col], errors='coerce')

categ = ['Property Type', 'District', 'Mukim', 'Scheme Name/Area', 'Tenure', 'Unit']
for col in categ:
    sales[col] = sales[col].astype('category')

sales['Month, Year of Transaction Date'] = pd.to_datetime(sales['Month, Year of Transaction Date'], errors='coerce')
In [10]:
sales.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2870 entries, 0 to 2869
Data columns (total 10 columns):
 #   Column                           Non-Null Count  Dtype         
---  ------                           --------------  -----         
 0   Property Type                    2870 non-null   category      
 1   District                         2870 non-null   category      
 2   Mukim                            2870 non-null   category      
 3   Scheme Name/Area                 2870 non-null   category      
 4   Month, Year of Transaction Date  2870 non-null   datetime64[ns]
 5   Tenure                           2870 non-null   category      
 6   Land Area                        2870 non-null   float64       
 7   Unit                             2870 non-null   category      
 8   Main Floor Area                  2870 non-null   float64       
 9   Transaction Price                2870 non-null   int64         
dtypes: category(6), datetime64[ns](1), float64(2), int64(1)
memory usage: 132.3 KB

Check missing values

In [11]:
sales.isna().sum()
Out[11]:
Property Type                      0
District                           0
Mukim                              0
Scheme Name/Area                   0
Month, Year of Transaction Date    0
Tenure                             0
Land Area                          0
Unit                               0
Main Floor Area                    0
Transaction Price                  0
dtype: int64

Based from the dataset, there is no missing values.

Data Cleaning

In [12]:
sales
Out[12]:
Property Type District Mukim Scheme Name/Area Month, Year of Transaction Date Tenure Land Area Unit Main Floor Area Transaction Price
0 1 - 1 1/2 Storey Terraced Alor Gajah Bdr Alor Gajah TAMAN SERI BAYU 2022-10-01 Leasehold 143.0 sq.m 85.84 200000
1 1 - 1 1/2 Storey Terraced Alor Gajah Bdr Masjid Tanah TAMAN BKT INDAH 2022-07-01 Freehold 143.0 sq.m 76.64 173000
2 1 - 1 1/2 Storey Terraced Alor Gajah Bdr Masjid Tanah TAMAN BKT INDAH 2022-09-01 Freehold 143.0 sq.m 77.01 210000
3 1 - 1 1/2 Storey Terraced Alor Gajah Belimbing TAMAN BELIMBING HARMONI 2022-10-01 Leasehold 232.0 sq.m 75.72 361111
4 1 - 1 1/2 Storey Terraced Alor Gajah Belimbing TAMAN VISTA BELIMBING 2022-01-01 Freehold 128.0 sq.m 83.61 230000
... ... ... ... ... ... ... ... ... ... ...
2865 2 - 2 1/2 Storey Terraced Melaka Tengah Tg Minyak TAMAN TG MINYAK UTAMA 2022-09-01 Freehold 205.0 sq.m 126.16 370000
2866 2 - 2 1/2 Storey Terraced Melaka Tengah Tg Minyak TAMAN TG MINYAK UTAMA 2022-10-01 Freehold 111.0 sq.m 126.16 290000
2867 2 - 2 1/2 Storey Terraced Melaka Tengah Ujong Pasir TAMAN KASTURI FASA 1 & 2 2022-01-01 Freehold 143.0 sq.m 133.40 555000
2868 2 - 2 1/2 Storey Terraced Melaka Tengah Ujong Pasir TAMAN SINN 2022-09-01 Freehold 200.0 sq.m 90.20 390000
2869 2 - 2 1/2 Storey Terraced Melaka Tengah Ujong Pasir TAMAN SINN 8 2022-03-01 Freehold 168.0 sq.m 205.45 660000

2870 rows × 10 columns

We have observed that the dataset expresses the 'Land Area' and 'Main Floor Area' in square meters (sq. meter). Although it is sufficient for performing exploratory data analysis, it is worth noting that square feet measurement is the most commonly used nomenclature in the real estate market to represent the size of a property.

We have convert the Land Area and Main Floor Area into square feet (sq.ft). Furthermore, we can conveniently rename the Land Area to Land Size and the Main Floor Area to Build Size.

Moreover, we have successfully transformed the column 'Month, Year of Transaction Date' into a date column.

In [13]:
sales['Land Size'] = sales['Land Area'] * 10.7639
sales['Build Size'] = sales['Main Floor Area'] * 10.7639
sales.drop(['Land Area', 'Main Floor Area'], axis=1, inplace=True)
sales
Out[13]:
Property Type District Mukim Scheme Name/Area Month, Year of Transaction Date Tenure Unit Transaction Price Land Size Build Size
0 1 - 1 1/2 Storey Terraced Alor Gajah Bdr Alor Gajah TAMAN SERI BAYU 2022-10-01 Leasehold sq.m 200000 1539.2377 923.973176
1 1 - 1 1/2 Storey Terraced Alor Gajah Bdr Masjid Tanah TAMAN BKT INDAH 2022-07-01 Freehold sq.m 173000 1539.2377 824.945296
2 1 - 1 1/2 Storey Terraced Alor Gajah Bdr Masjid Tanah TAMAN BKT INDAH 2022-09-01 Freehold sq.m 210000 1539.2377 828.927939
3 1 - 1 1/2 Storey Terraced Alor Gajah Belimbing TAMAN BELIMBING HARMONI 2022-10-01 Leasehold sq.m 361111 2497.2248 815.042508
4 1 - 1 1/2 Storey Terraced Alor Gajah Belimbing TAMAN VISTA BELIMBING 2022-01-01 Freehold sq.m 230000 1377.7792 899.969679
... ... ... ... ... ... ... ... ... ... ...
2865 2 - 2 1/2 Storey Terraced Melaka Tengah Tg Minyak TAMAN TG MINYAK UTAMA 2022-09-01 Freehold sq.m 370000 2206.5995 1357.973624
2866 2 - 2 1/2 Storey Terraced Melaka Tengah Tg Minyak TAMAN TG MINYAK UTAMA 2022-10-01 Freehold sq.m 290000 1194.7929 1357.973624
2867 2 - 2 1/2 Storey Terraced Melaka Tengah Ujong Pasir TAMAN KASTURI FASA 1 & 2 2022-01-01 Freehold sq.m 555000 1539.2377 1435.904260
2868 2 - 2 1/2 Storey Terraced Melaka Tengah Ujong Pasir TAMAN SINN 2022-09-01 Freehold sq.m 390000 2152.7800 970.903780
2869 2 - 2 1/2 Storey Terraced Melaka Tengah Ujong Pasir TAMAN SINN 8 2022-03-01 Freehold sq.m 660000 1808.3352 2211.443255

2870 rows × 10 columns

In [14]:
sales=sales[['Property Type','District','Mukim','Scheme Name/Area','Month, Year of Transaction Date', 'Tenure', 'Land Size', 'Unit', 'Build Size', 'Transaction Price']]
sales
Out[14]:
Property Type District Mukim Scheme Name/Area Month, Year of Transaction Date Tenure Land Size Unit Build Size Transaction Price
0 1 - 1 1/2 Storey Terraced Alor Gajah Bdr Alor Gajah TAMAN SERI BAYU 2022-10-01 Leasehold 1539.2377 sq.m 923.973176 200000
1 1 - 1 1/2 Storey Terraced Alor Gajah Bdr Masjid Tanah TAMAN BKT INDAH 2022-07-01 Freehold 1539.2377 sq.m 824.945296 173000
2 1 - 1 1/2 Storey Terraced Alor Gajah Bdr Masjid Tanah TAMAN BKT INDAH 2022-09-01 Freehold 1539.2377 sq.m 828.927939 210000
3 1 - 1 1/2 Storey Terraced Alor Gajah Belimbing TAMAN BELIMBING HARMONI 2022-10-01 Leasehold 2497.2248 sq.m 815.042508 361111
4 1 - 1 1/2 Storey Terraced Alor Gajah Belimbing TAMAN VISTA BELIMBING 2022-01-01 Freehold 1377.7792 sq.m 899.969679 230000
... ... ... ... ... ... ... ... ... ... ...
2865 2 - 2 1/2 Storey Terraced Melaka Tengah Tg Minyak TAMAN TG MINYAK UTAMA 2022-09-01 Freehold 2206.5995 sq.m 1357.973624 370000
2866 2 - 2 1/2 Storey Terraced Melaka Tengah Tg Minyak TAMAN TG MINYAK UTAMA 2022-10-01 Freehold 1194.7929 sq.m 1357.973624 290000
2867 2 - 2 1/2 Storey Terraced Melaka Tengah Ujong Pasir TAMAN KASTURI FASA 1 & 2 2022-01-01 Freehold 1539.2377 sq.m 1435.904260 555000
2868 2 - 2 1/2 Storey Terraced Melaka Tengah Ujong Pasir TAMAN SINN 2022-09-01 Freehold 2152.7800 sq.m 970.903780 390000
2869 2 - 2 1/2 Storey Terraced Melaka Tengah Ujong Pasir TAMAN SINN 8 2022-03-01 Freehold 1808.3352 sq.m 2211.443255 660000

2870 rows × 10 columns

In [15]:
sales['Unit'].replace('sq.m', 'sq.ft', inplace=True)
sales
Out[15]:
Property Type District Mukim Scheme Name/Area Month, Year of Transaction Date Tenure Land Size Unit Build Size Transaction Price
0 1 - 1 1/2 Storey Terraced Alor Gajah Bdr Alor Gajah TAMAN SERI BAYU 2022-10-01 Leasehold 1539.2377 sq.ft 923.973176 200000
1 1 - 1 1/2 Storey Terraced Alor Gajah Bdr Masjid Tanah TAMAN BKT INDAH 2022-07-01 Freehold 1539.2377 sq.ft 824.945296 173000
2 1 - 1 1/2 Storey Terraced Alor Gajah Bdr Masjid Tanah TAMAN BKT INDAH 2022-09-01 Freehold 1539.2377 sq.ft 828.927939 210000
3 1 - 1 1/2 Storey Terraced Alor Gajah Belimbing TAMAN BELIMBING HARMONI 2022-10-01 Leasehold 2497.2248 sq.ft 815.042508 361111
4 1 - 1 1/2 Storey Terraced Alor Gajah Belimbing TAMAN VISTA BELIMBING 2022-01-01 Freehold 1377.7792 sq.ft 899.969679 230000
... ... ... ... ... ... ... ... ... ... ...
2865 2 - 2 1/2 Storey Terraced Melaka Tengah Tg Minyak TAMAN TG MINYAK UTAMA 2022-09-01 Freehold 2206.5995 sq.ft 1357.973624 370000
2866 2 - 2 1/2 Storey Terraced Melaka Tengah Tg Minyak TAMAN TG MINYAK UTAMA 2022-10-01 Freehold 1194.7929 sq.ft 1357.973624 290000
2867 2 - 2 1/2 Storey Terraced Melaka Tengah Ujong Pasir TAMAN KASTURI FASA 1 & 2 2022-01-01 Freehold 1539.2377 sq.ft 1435.904260 555000
2868 2 - 2 1/2 Storey Terraced Melaka Tengah Ujong Pasir TAMAN SINN 2022-09-01 Freehold 2152.7800 sq.ft 970.903780 390000
2869 2 - 2 1/2 Storey Terraced Melaka Tengah Ujong Pasir TAMAN SINN 8 2022-03-01 Freehold 1808.3352 sq.ft 2211.443255 660000

2870 rows × 10 columns

Latitude and Longitude Positions

Before creating an interactive map, it is necessary to acquire the approximate latitude and longitude positions for each scheme name/area. As these positions are not included in the dataset, we can obtain them through the integration API between portal postcode.my and Google Maps.

In [21]:
latlong=pd.read_csv('C:/Users/KEMAS/myproject/latlong.csv')
latlong
Out[21]:
Scheme Name/Area Lat Long
0 TAMAN SERI BAYU 2.384740 102.212509
1 TAMAN BKT INDAH 2.350550 102.103860
2 TAMAN BKT INDAH 2.350550 102.103860
3 TAMAN BELIMBING HARMONI 2.335506 102.266894
4 TAMAN VISTA BELIMBING 2.328142 102.266958
... ... ... ...
2865 TAMAN TG MINYAK UTAMA 2.268306 102.194419
2866 TAMAN TG MINYAK UTAMA 2.268306 102.194419
2867 TAMAN KASTURI FASA 1 & 2 2.192962 102.272744
2868 TAMAN SINN 2.194609 102.270545
2869 TAMAN SINN 8 2.191429 102.274285

2870 rows × 3 columns

The portal provides access to 457 scheme names/areas, which can be leveraged to generate positions. However, the original dataset requires the integration of latitude and longitude positions to facilitate this process.

In [22]:
latlong.drop(['Scheme Name/Area'], axis=1, inplace=True)
latlong
Out[22]:
Lat Long
0 2.384740 102.212509
1 2.350550 102.103860
2 2.350550 102.103860
3 2.335506 102.266894
4 2.328142 102.266958
... ... ...
2865 2.268306 102.194419
2866 2.268306 102.194419
2867 2.192962 102.272744
2868 2.194609 102.270545
2869 2.191429 102.274285

2870 rows × 2 columns

In [23]:
latlong.isna().sum()
Out[23]:
Lat     0
Long    0
dtype: int64
In [24]:
new_sales = sales.merge(latlong, left_index=True, right_index=True)
new_sales
Out[24]:
Property Type District Mukim Scheme Name/Area Month, Year of Transaction Date Tenure Land Size Unit Build Size Transaction Price Lat Long
0 1 - 1 1/2 Storey Terraced Alor Gajah Bdr Alor Gajah TAMAN SERI BAYU 2022-10-01 Leasehold 1539.2377 sq.ft 923.973176 200000 2.384740 102.212509
1 1 - 1 1/2 Storey Terraced Alor Gajah Bdr Masjid Tanah TAMAN BKT INDAH 2022-07-01 Freehold 1539.2377 sq.ft 824.945296 173000 2.350550 102.103860
2 1 - 1 1/2 Storey Terraced Alor Gajah Bdr Masjid Tanah TAMAN BKT INDAH 2022-09-01 Freehold 1539.2377 sq.ft 828.927939 210000 2.350550 102.103860
3 1 - 1 1/2 Storey Terraced Alor Gajah Belimbing TAMAN BELIMBING HARMONI 2022-10-01 Leasehold 2497.2248 sq.ft 815.042508 361111 2.335506 102.266894
4 1 - 1 1/2 Storey Terraced Alor Gajah Belimbing TAMAN VISTA BELIMBING 2022-01-01 Freehold 1377.7792 sq.ft 899.969679 230000 2.328142 102.266958
... ... ... ... ... ... ... ... ... ... ... ... ...
2865 2 - 2 1/2 Storey Terraced Melaka Tengah Tg Minyak TAMAN TG MINYAK UTAMA 2022-09-01 Freehold 2206.5995 sq.ft 1357.973624 370000 2.268306 102.194419
2866 2 - 2 1/2 Storey Terraced Melaka Tengah Tg Minyak TAMAN TG MINYAK UTAMA 2022-10-01 Freehold 1194.7929 sq.ft 1357.973624 290000 2.268306 102.194419
2867 2 - 2 1/2 Storey Terraced Melaka Tengah Ujong Pasir TAMAN KASTURI FASA 1 & 2 2022-01-01 Freehold 1539.2377 sq.ft 1435.904260 555000 2.192962 102.272744
2868 2 - 2 1/2 Storey Terraced Melaka Tengah Ujong Pasir TAMAN SINN 2022-09-01 Freehold 2152.7800 sq.ft 970.903780 390000 2.194609 102.270545
2869 2 - 2 1/2 Storey Terraced Melaka Tengah Ujong Pasir TAMAN SINN 8 2022-03-01 Freehold 1808.3352 sq.ft 2211.443255 660000 2.191429 102.274285

2870 rows × 12 columns

In [25]:
new_sales=new_sales[['Property Type','District','Mukim','Scheme Name/Area', 'Lat', 'Long', 'Month, Year of Transaction Date', 'Tenure', 'Land Size', 'Unit', 'Build Size', 'Transaction Price']]
new_sales
Out[25]:
Property Type District Mukim Scheme Name/Area Lat Long Month, Year of Transaction Date Tenure Land Size Unit Build Size Transaction Price
0 1 - 1 1/2 Storey Terraced Alor Gajah Bdr Alor Gajah TAMAN SERI BAYU 2.384740 102.212509 2022-10-01 Leasehold 1539.2377 sq.ft 923.973176 200000
1 1 - 1 1/2 Storey Terraced Alor Gajah Bdr Masjid Tanah TAMAN BKT INDAH 2.350550 102.103860 2022-07-01 Freehold 1539.2377 sq.ft 824.945296 173000
2 1 - 1 1/2 Storey Terraced Alor Gajah Bdr Masjid Tanah TAMAN BKT INDAH 2.350550 102.103860 2022-09-01 Freehold 1539.2377 sq.ft 828.927939 210000
3 1 - 1 1/2 Storey Terraced Alor Gajah Belimbing TAMAN BELIMBING HARMONI 2.335506 102.266894 2022-10-01 Leasehold 2497.2248 sq.ft 815.042508 361111
4 1 - 1 1/2 Storey Terraced Alor Gajah Belimbing TAMAN VISTA BELIMBING 2.328142 102.266958 2022-01-01 Freehold 1377.7792 sq.ft 899.969679 230000
... ... ... ... ... ... ... ... ... ... ... ... ...
2865 2 - 2 1/2 Storey Terraced Melaka Tengah Tg Minyak TAMAN TG MINYAK UTAMA 2.268306 102.194419 2022-09-01 Freehold 2206.5995 sq.ft 1357.973624 370000
2866 2 - 2 1/2 Storey Terraced Melaka Tengah Tg Minyak TAMAN TG MINYAK UTAMA 2.268306 102.194419 2022-10-01 Freehold 1194.7929 sq.ft 1357.973624 290000
2867 2 - 2 1/2 Storey Terraced Melaka Tengah Ujong Pasir TAMAN KASTURI FASA 1 & 2 2.192962 102.272744 2022-01-01 Freehold 1539.2377 sq.ft 1435.904260 555000
2868 2 - 2 1/2 Storey Terraced Melaka Tengah Ujong Pasir TAMAN SINN 2.194609 102.270545 2022-09-01 Freehold 2152.7800 sq.ft 970.903780 390000
2869 2 - 2 1/2 Storey Terraced Melaka Tengah Ujong Pasir TAMAN SINN 8 2.191429 102.274285 2022-03-01 Freehold 1808.3352 sq.ft 2211.443255 660000

2870 rows × 12 columns

🔶 Insights: We have combined the latitude and longitute into the dataset_2022.csv and renamed it to melaka_terraced_property_sales_2022.csv.

Let's explore Melaka Property Sales Year 2022 with useful statistics, now that the dataset has been processed to the desired format.

In [27]:
new_sales.to_csv('melaka_terraced_property_sales_2022.csv', index=False)
new_sales.to_csv('C:/Users/KEMAS/myproject/melaka_terraced_property_sales_2022.csv')

2.0 Data Visualizations

Statistics

In [28]:
numerical_variables =  new_sales.select_dtypes(include=['number']).columns
columns_to_exclude = ['Property Type','District','Mukim','Scheme Name/Area','Lat','Long','Month, Year of Transaction Date','Unit']
statistics = new_sales.drop(columns=columns_to_exclude).describe().round(2)

column_sums = new_sales[numerical_variables].sum()
statistics.loc['sum'] = column_sums

def format_accounting(value):
    return "RM{:,.2f}".format(value)

formatted_statistics = statistics.style.format({
    'Transaction Price': format_accounting
})

formatted_statistics = formatted_statistics.background_gradient()

dfi.export(formatted_statistics, 'formatted_statistics.png')

formatted_statistics
Out[28]:
  Land Size Build Size Transaction Price
count 2870.000000 2870.000000 RM2,870.00
mean 1643.010000 1149.640000 RM302,953.82
std 633.460000 447.150000 RM121,401.47
min 143.000000 520.000000 RM90,000.00
25% 1302.430000 819.990000 RM225,000.00
50% 1528.470000 989.960000 RM270,000.00
75% 1679.170000 1369.110000 RM363,675.00
max 8438.900000 4260.030000 RM1,200,000.00
sum 4715451.098807 3299474.606600 RM869,477,476.00

Based on the statistics summary provided, it appears that there were a total of 2,870 transactions in 2022. The highest transaction price was RM1.2 million, while the lowest was RM90,000.00. The average transaction price comes in at RM302,953.82. As the dataset pertains to both single storey and double storey terraced houses, it may be helpful to visualize the information according to each property type.

Boxplots

In [32]:
from matplotlib import pyplot as plt
import seaborn as sns
g = sns.FacetGrid(new_sales, col="Property Type", col_wrap=2, height=5, sharex=False, sharey=False)
g.map_dataframe(sns.boxplot, x='District', y='Transaction Price', hue='Tenure', palette='Blues')
g.add_legend(title='Tenure')
g.set_xticklabels(rotation=90)
g.set_axis_labels('District', 'Transaction Price in RM')
g.fig.subplots_adjust(top=0.9)
g.fig.suptitle('Boxplots for Transaction Price by District, Tenure and Property Type')
plt.show()

plt.savefig('Boxplot_for_Transaction_Price.png')
<Figure size 640x480 with 0 Axes>

The boxplots depicted above showcase the various property types segregated by districts. Additionally, the boxplots also portray the single storey and double storey terraced houses based on their land status, be it Freehold or Leasehold. Despite the presence of outliers in the boxplots, we have decided to include them for better visualization on the map.

Heatmap of Property Type vs District

In [33]:
from matplotlib import pyplot as plt
plt.subplots(figsize=(8, 8))
df_2dhist = pd.DataFrame({
    x_label: grp['District'].value_counts()
    for x_label, grp in new_sales.groupby('Property Type')
})
sns.heatmap(df_2dhist, cmap='Purples', annot=True, fmt='g')
plt.xlabel('Property Type')
plt.ylabel('District')
plt.title('Heatmap of Property Type vs District')
plt.show()

plt.savefig('Heatmap_District_Type.png')
<Figure size 640x480 with 0 Axes>
In [34]:
property_types_to_filter = ['1 - 1 1/2 Storey Terraced', '2 - 2 1/2 Storey Terraced']
new_district_counts_combined = new_sales[new_sales['Property Type'].isin(property_types_to_filter)] \
    .groupby(['Property Type', 'District']) \
    .size() \
    .unstack(fill_value=0)
new_district_counts_combined['Total'] = new_district_counts_combined.sum(axis=1)
new_district_counts_combined.loc['Overall'] = new_district_counts_combined.sum(axis=0)

print(new_district_counts_combined)
dfi.export(new_district_counts_combined, 'type_counts.png')
District                   Alor Gajah  Jasin  Melaka Tengah  Total
Property Type                                                     
1 - 1 1/2 Storey Terraced         375    471            969   1815
2 - 2 1/2 Storey Terraced         313     96            646   1055
Overall                           688    567           1615   2870

The heatmap displayed above provides a comparison of property types and districts. In 2022, Melaka Tengah had the highest number of single storey terraced houses sold with 969 units, while Jasin had 471 units and Alor Gajah had 375 units. On the other hand, Melaka Tengah also had the highest number of double storey terraced houses sold with 646 units, followed by Alor Gajah with 313 units and Jasin with 96 units.

In total, single storey terraced houses were sold more frequently with 1815 units compared to double storey terraced houses with 1055 units.

Heatmap of District vs Tenure

In [35]:
plt.subplots(figsize=(8, 8))
df_2dhist = pd.DataFrame({
    x_label: grp['Tenure'].value_counts()
    for x_label, grp in new_sales.groupby('District')
})
sns.heatmap(df_2dhist, cmap='Blues', annot=True, fmt='g')
plt.xlabel('District')
plt.ylabel('Tenure')
plt.title('Heatmap of District vs Tenure')
plt.show()

plt.savefig('Heatmap_District_Tenure.png')
<Figure size 640x480 with 0 Axes>
In [36]:
tenure_to_filter = ['Freehold', 'Leasehold']
district_counts_combined = new_sales[new_sales['Tenure'].isin(tenure_to_filter)] \
    .groupby(['District', 'Tenure']) \
    .size() \
    .unstack(fill_value=0)
district_counts_combined['Total'] = district_counts_combined.sum(axis=1)
district_counts_combined.loc['Overall'] = district_counts_combined.sum(axis=0)
print(district_counts_combined)


dfi.export(district_counts_combined, 'district_counts.png')
Tenure         Freehold  Leasehold  Total
District                                 
Alor Gajah          468        220    688
Jasin               311        256    567
Melaka Tengah       854        761   1615
Overall            1633       1237   2870

Looking at the heatmap charting district against tenure, it's clear that the largest number of transactions took place in Melaka Tengah, where 1615 units were sold. Alor Gajah saw the second-highest number of transactions at 688 units, followed by Jasin at 567 units.

In terms of tenure, it seems that freehold properties were the most popular, with 1633 transactions, including 854 from Melaka Tengah, 468 from Jasin, and 311 from Alor Gajah. Leasehold residentials, on the other hand, saw 1237 transactions, including 761 units from Melaka Tengah, 256 from Jasin, and 220 from Alor Gajah.

Interactive Map

Map 1: Hotspots for overall locations

From the latitude and longitude information, we can create a scatter plot using the plotly.express package to visualize the approximate positions of each scheme name/area. While the interactive features are not available here, running the codes can be quite intriguing. You can gather some information simply by hovering over the map.

In [37]:
import plotly.express as px

fig = px.scatter_mapbox(new_sales, lat='Lat', lon='Long', color='Transaction Price', size='Transaction Price',  hover_data= {'Scheme Name/Area': True, 'District': True, 'Build Size': True},
                        color_continuous_scale=px.colors.sequential.Viridis, mapbox_style='carto-positron', size_max=15, zoom=10)

fig.update_layout(mapbox_style='open-street-map')
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()

From the figure above, we can see that the yellow circle represents a higher transaction price and is easily located on the map. The position of the yellow circle represents the location of the highest value transaction in Taman Residence Lapan, Melaka Tengah.

Map 2: Hotspots for overall transactions

In [138]:
new_sales['Transaction Count'] = new_sales.groupby('Scheme Name/Area')['Transaction Price'].transform('count')

fig = px.scatter_mapbox(new_sales, lat='Lat', lon='Long', 
                        color='Transaction Count',
                        size='Transaction Count',
                        color_continuous_scale=px.colors.sequential.thermal,
                        hover_data= {'Scheme Name/Area': True, 'District': True, 'Build Size': True, 'Transaction Price': True},
                        size_max=15, zoom=10,
                        mapbox_style='carto-positron')
fig.update_layout(mapbox_style='open-street-map')
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()

The most concentrated dots are located in Melaka Tengah, which is near the central business district (CBD), followed by Bandar Botani Parkland with 124 transactions in 2022.

The highest number of transactions (154) were recorded in Taman Scientex (Bukit Tambun Perdana) in proximity to Durian Tunggal and Alor Gajah.

Map 3: Hotspots for Single Storey Locations

In [124]:
single_storey_filtered = new_sales[new_sales['Property Type'] == '1 - 1 1/2 Storey Terraced']
fig = px.scatter_mapbox(single_storey_filtered, lat='Lat', lon='Long', color='Transaction Price', size='Transaction Price', hover_data= {'Scheme Name/Area': True, 'District': True, 'Build Size': True},
                        color_continuous_scale=px.colors.sequential.Viridis, mapbox_style='carto-positron', size_max=15, zoom=10)

fig.update_layout(mapbox_style='open-street-map')
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()

Figure above displays the locations for every single storey terraced sold in 2022. Ideally, Melaka Tengah seems to be very active in terms of populated dots on the map.

Map 4: Hotspots for Single Storey Transactions

In [139]:
single_storey_filtered['Transaction Count'] = new_sales.groupby('Scheme Name/Area')['Transaction Price'].transform('count')

fig = px.scatter_mapbox(single_storey_filtered, lat='Lat', lon='Long', 
                        color='Transaction Count',
                        size='Transaction Count',
                        color_continuous_scale=px.colors.sequential.thermal,
                        hover_data= {'Scheme Name/Area': True, 'District': True, 'Build Size': True, 'Transaction Price': True},
                        size_max=15, zoom=10,
                        mapbox_style='carto-positron')
fig.update_layout(mapbox_style='open-street-map')
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()

However, records show that Jasin was attractive enough to pull homebuyers in 2022. The transactions count were recorded at 124 in Botani Parkland alone. Additionally, high value residential such Country Villa in Jasin was also contributing atleast 44 transactions.

Map 5: Hotspots for Double Storey Locations

In 2022, 1085 units of double storey terraced were sold in Melaka. Although Taman Anggerik (Lot 71) in Melaka Tengah recorded the highest market value for double storey of RM390,000.00 but it has serious contender from Jasin which is Country Villas at RM380,000.00. Both the residentials have almost identical build size of 1537.95 and 1471.75 respectively.

In [126]:
double_storey_filtered = new_sales[new_sales['Property Type'] == '2 - 2 1/2 Storey Terraced']
fig = px.scatter_mapbox(single_storey_filtered, lat='Lat', lon='Long', color='Transaction Price', size='Transaction Price', hover_data= {'Scheme Name/Area': True, 'District': True, 'Build Size': True},
                        color_continuous_scale=px.colors.sequential.Viridis, mapbox_style='carto-positron', size_max=15, zoom=10)

fig.update_layout(mapbox_style='open-street-map')
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()

Map 6: Hotspots for Double Storey Transactions

In [141]:
double_storey_filtered['Transaction Count'] = new_sales.groupby('Scheme Name/Area')['Transaction Price'].transform('count')

fig = px.scatter_mapbox(double_storey_filtered, lat='Lat', lon='Long', 
                        color='Transaction Count',
                        size='Transaction Count',
                        color_continuous_scale=px.colors.sequential.thermal,
                        hover_data= {'Scheme Name/Area': True, 'District': True, 'Build Size': True, 'Transaction Price': True},
                        size_max=15, zoom=10,
                        mapbox_style='carto-positron')
fig.update_layout(mapbox_style='open-street-map')
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()

Nevertheless, Alor Gajah seems has stole a spotlight since the highest transactions count was recorded in Taman Scientex (Bukit Tambun Perdana). The new development in Alor Gajah has managed to attract homebuyers to settle in the district.

3. The Insights

Regression Analysis

In [208]:
plt.title('Transaction Price Distribution Plot')
sns.distplot(new_sales['Transaction Price'])
plt.show()
In [250]:
plt.title('Build Size Distribution Plot')
sns.distplot(new_sales['Build Size'])
plt.show()

Based on the density plot shown above, it's clear that the majority of transactions fall within the price range of RM200,000.00 to RM300,000.00. Additionally, the graph highlights that the density of build size is concentrated between 800 sq.ft and 900 sq.ft. These patterns suggest a high demand for residential properties within this specific price and build size range. By utilizing a linear regression model and the sklearn.linear_model package, we were able to calculate the coefficients for both dependent and independent variables.

The computed results are as follows: Coefficient - [195.0251, 55.3691] and Intercept - 12227.5884. Thus, the regression can be represent as in the model below:

In [38]:
from sklearn.linear_model import LinearRegression

X = new_sales[['Build Size', 'Land Size']]
y = new_sales['Transaction Price']

model = LinearRegression()

model.fit(X, y)

print('Coefficients:', model.coef_)
print('Intercept:', model.intercept_)
Coefficients: [195.02512463  55.36908406]
Intercept: -12227.588369571953

The MLR model is $$Y = \beta_0 + \beta_1 X_1 + \beta_2 X_2$$

$$Price = -12227.5884 + 195.0251 (Build Size) + 55.3691 (Land Size)$$
In [39]:
Price = -12227.588369571662 + 55.36908406 * 1643.01 + 195.02512463 * 1149.64
Price
Out[39]:
302953.05471148214

Recommendations

Utilize Interactive Map for Market Analysis

Housing developers should leverage the interactive map to conduct in-depth market analysis by exploring transaction patterns, pricing trends and demand hotspots across different scheme name/areas in Melaka. This will facilitate informed decision-making in formulating pricing strategies and identifying lucrative development opportunities.

Monitor Future Development Projects

Given the anticipated growth momentum in Melaka's property market, it's crucial for developers to closely monitor upcoming development projects such as Melaka Waterfront Economic Zone (MWEZ) and Harbour City Melaka. These projects are expected to drive demand and reshape the landscape of the property market, presenting potential investment opportunities.

Adapt Business Strategies

Based on the insights derived from the interactive map and market analysis, housing developers should adapt their business strategies accordingly. This may involve diversifying product offerings, targeting specific customer segments, or adjusting pricing strategies to remain competitive in the dynamic market landscape.

Enhance Customer Engagement

The interactive map can also serve as a valuable tool for enhancing customer engagement and marketing efforts. Developers can leverage the map to provide potential buyers with detailed information about available properties, amenities and surrounding infrastructure, thereby improving transparency and fostering trust with customers.

Collaborate with Stakeholders

Collaboration with local authorities, real estate agencies and other stakeholders can further enhance the effectiveness of the interactive map and promote sustainable growth in the property market. By sharing data and insights, stakeholders can collectively address challenges, identify opportunities and contribute to the overall development of Melaka's property sector.

Conclusion

In conclusion, the development of an interactive map for single and double storey terraced property sales in Melaka for the year 2022 offers valuable insights and opportunities for housing developers. A comprehensive dataset covering transaction details, property attributes and geographic information, developers can gain a deeper understanding of market dynamics and consumer preferences.

The analysis revealed that Melaka's property market recorded significant transactions in 2022, with single and double storey terraced properties accounting for a substantial portion of the market activity. Key insights such as pricing trends, demand hotspots and upcoming development projects provide developers with actionable information to formulate effective business strategies and capitalize on emerging opportunities.

Moving forward, it is recommended that developers leverage the interactive map to conduct detailed market analysis, monitor future development projects, adapt business strategies, enhance customer engagement and collaborate with stakeholders. By doing so, developers can navigate the evolving property landscape in Melaka and drive sustainable growth in the industry.

In [ ]: